const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  //存储promise的状态值
  static = PENDING;
  //存储promise的返回值
  value = undefined;
  //存储promise的错误信息
  reason = undefined;

  //存储异步调用的回调函数
  successCallback = [];
  failCallback = [];

  resolve = (value) => {
    if (this.static !== PENDING) return;
    this.static = FULFILLED;
    this.value = value;
    while (this.successCallback.length) {
      this.successCallback.shift()();
    }

    //this.successCallback && this.successCallback(this.value);
  };
  reject = (reason) => {
    if (this.static !== PENDING) return;
    this.static = REJECTED;
    this.reason = reason;
    while (this.failCallback.length) this.failCallback.shift()();
    //this.failCallback && this.failCallback(this.reason);
  };
  then(successCallback, failCallback) {
    successCallback = successCallback ? successCallback : (v) => v;
    failCallback = failCallback
      ? failCallback
      : (v) => {
          throw v;
        };
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.static === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
        // resolve(x);
      } else if (this.static === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);

        // reject(r);
      } else {
        // this.successCallback.push(successCallback);
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
    return promise2;
  }
  finally(callback) {
    return this.then(
      (value) => {
        return MyPromise.resolve(callback().then(() => value));
        // callback();
        // return value;
      },
      (reason) => {
        return MyPromise.resolve(
          callback().then(() => {
            throw reason;
          })
        );
        // callback();
        // throw reason;
      }
    );
  }
  catch(failCallback) {
    return this.then(undefined, failCallback);
  }
  static all(array) {
    let result = [];
    let index = 0;

    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value;
        index++;
        if (index === array.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          current.then(
            (value) => addData(i, value),
            (r) => reject(r)
          );
        } else {
          addData(i, array[i]);
        }
      }
    });
  }
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((r) => r(value));
  }
}

//判断x值是否是promise对象
//如果是promise对象
function resolvePromise(newPromise, x, resolve, reject) {
  //   console.log(newPromise === x);
  if (newPromise === x) {
    return reject(new TypeError("循环调用Promise"));
  }
  if (x instanceof MyPromise) {
    // x.then(
    //   (vale) => resolve(value),
    //   (reason) => reject(reason)
    // );
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}
module.exports = MyPromise;
